#!/usr/bin/perl
use strict;
use loft;
use Digest::MD5;
our $ver='0.3';
my ($target,$tver)=('My Little Pony by GameLoft', '1.2.1');
my $dfile='/mnt/sdcard/Android/data/com.gameloft.android.ANMP.GloftPOHM/files/main.1200.com.gameloft.android.ANMP.GloftPOHM.obb';
my $subject=<<EOF;
1.3 - added lottery winner patch
1.2 - fix for busybox use.
some patch update for more usability
lottery game update
1.1 - ver 1.2.1
1.0 - ver 1.0.5
- earn money, hearts and diamonds by plying with pony in minigames
- speed, gametime, experience in minigames are increased
EOF
my $mtime=scalar localtime;
my $size=-s $IN;
die "$IN size differs from $OUT size ($size)" if $size != -s $OUT;
my $src = Digest::MD5->new;
my $dst = Digest::MD5->new;
my $tot = Digest::MD5->new;

open IN;
open OUT;
binmode IN;
binmode OUT;

my $blk=512;
my $bskip=8;
our $WR="../pony_$tver.sh";
open WR,'>',$WR or die "$WR: $!";
binmode WR;
chmod 0755,$WR;
#sysseek WR,$blk*$bskip,0;

my (@d,$np,$p,$cnt);
for(my $n=$cnt=$np=0;;$n++)
{
my ($a,$b);
sysread IN,$a,$blk or last;
sysread OUT,$b,$blk or last;
$src->add($a);
$dst->add($b);
next if $a eq $b;
$cnt++;
if (defined $p && $np==$n-1){$p->[1]++;$p->[2].=$b;$p->[3].=$a}
else {
$tot->add($p->[2].$p->[3]) if $p;
push @d,$p=[$n,1,$b,$a]}
$np=$n;
#$_=$b.$a;
#syswrite WR,$_;
#$tot->add($_);
}
$tot->add($p->[2].$p->[3]) if $p;

$src=$src->hexdigest;
$dst=$dst->hexdigest;
$tot=$tot->hexdigest;

=head
# some autoconfiguration. We need:
# a) dd tool with support "conv=notrunc" flag
# b) shell with function{} support. bash is ideal, mksh is also OK
# c) md5sum tool. 

[ -z "$dd" ] && {

	for dd in '' /system/bin/busybox /data/local/busybox /data/local/bin/busybox
	do break;done;

	[[ -x /system/bin/busybox ]] && dd="/system/bin/busybox dd"
	[[ -z $dd -x /data/local/busybox ]] && dd
}

=cut
$cnt*=2;
my $index=<<EOF;
#!/system/bin/sh

# some global configs
blk=$blk	# size of block in bytes
beg=$bskip	# beginning of the path in this file
cnt=$cnt	# count of path blocks

# preconfigs
[[ -e ~/.patch_cache ]] && . ~/.patch_cache
rev=\${rev:-0}	# reverse patch - 0=direct patch, 1=checking source (recommended), 2=writing without test
dd=\${dd:-dd}	# full path of dd
md5=\${md5:-md5sum -b}	# .. of md5sum
show=\${show:-0}		# display dd commands used

############ PAD

showdd  () { ((show>0)) && echo "\$dd \$*" >&2;[ "\$show" -lt 2 -o -z "\$8" ] && \$dd \$* 2>/dev/null;}
dcut () { showdd bs=\$blk conv=notrunc count=\$cnt if="\$src\" skip=\$*;}
dsum () { SUM=`dcut \$* | \$md5 | cut '-d ' -f1`;}
# if previous fails - consider using other shell - like mksh

#### DO NOT CHANGE OFFSETS AFTER THIS SCRIPT ####

size=$size # in bytes
xsum_src=$src
xsum_dst=$dst
xsum_our=$tot # after script

# filenames
src=\${src:-\$0}
############ PAD
dst=\${dst:-$dfile}
############ PAD

echo "Binary Shell Patch for Android
Made with Patch Generator v$ver by vGimly

Target      : $target \[$tver]
Generated   : $mtime
Subject     : $subject
File        : \$dst
md5 original: \$xsum_src
md5 patched : \$xsum_dst
Size (bytes): \$size
" >&2

# self-check:
dsum \$beg
if [[ \$SUM = \$xsum_our ]]; then echo Patch integrity OK
else echo "Patch file \$src sum \$SUM!=\$xsum_our."
[[ -z \$forced ]] && select rpl in "Ignore and continue" Exit;do [[ \$rpl != 1 ]] && echo Ignored && break;echo Aborted;exit;done
fi

# simple check dst-file (only size)
dst_size=`stat -Lc%s "\$dst"`
((dst_size!=size)) && echo "File \$dst size \$dst_size!=\$size" && exit
((check>0)) && \$md5 "\$dst"

# main patch proc:
function xdd { cnt=\${3:-1}; off=\$((\$1*2+beg)); is=\$((off+cnt))
  dsum \$off			&& sum_src=\$SUM
  dsum \$is				&& sum_def=\$SUM
  dsum \$2 if="\$dst"	&& sum_dst=\$SUM
  echo -n "Hunk #\$1 at offset \$2 * \$blk = \$((\$2 * blk)) x \$cnt is "
  ((show>0)) && echo -n "dst=\$sum_dst[\$2/d] orig=\$sum_def[\$is] patch=\$sum_src[\$off] "

  # some sanity check
  [ -z "\$sum_src" -o -z "\$sum_dst" -o -z "\$sum_def" -o "\$sum_def" = "\$sum_src" ] && echo "Error in sum" && return

  if   [[ \$sum_dst = \$sum_def ]];then is=0;echo -n unpatched
  elif [[ \$sum_dst = \$sum_src ]];then is=1;echo -n patched
  else is=1;echo -n weird
  fi
  ((rev>1)) && is=1
  if ((is==rev)) || ((rev>1))
  then if ((is==0));then echo " - Applying..";else echo " - Undoing..";fi
  dcut \$((off+(is*cnt))) seek=\$2 of="\$dst" && changed=1
  else echo " - SKIPPED!";return
  fi
}

# Execute patch:
EOF

$np=0;
foreach $p (@d)
{my ($idx,$cnt)=@$p;$index.=sprintf " xdd %u %u%s\n", $np, $idx, $cnt>1?" $cnt":'';$np+=$cnt}

$index.=<<EOF;
if ((changed)); then ((check>0)) && \$md5 "\$dst";else echo "Nothing changed";fi
exit
cat > /dev/null << Some_Protection_Is_Here_\$RANDOM\n
EOF

my $end=$blk*$bskip;
my $tail=sprintf "\n## THE END OF THE PAD ##\nAfter newline here must be offset of %u (0x%04x):>\n",$end,$end;
$np=length $index.$tail;
die "Script length is over $end bytes ($np). Consider to give me moar bytes" if $np > $end;
$np=$end-$np;
sysseek WR,0,0;
syswrite WR,$index.('#'x $np).$tail;
foreach $p (@d){syswrite WR,$p->[2].$p->[3]}
close WR;
